package cn.iocoder.yudao.module.shop.revenue.service.core;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.business.basic.service.impl.AbstractService;
import cn.iocoder.yudao.framework.common.exception.Assertions;
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
import cn.iocoder.yudao.module.api.shop.info.ShopInfoApi;
import cn.iocoder.yudao.module.api.shop.revenue.enums.RevenueStatusEnum;
import cn.iocoder.yudao.module.api.shop.revenue.vo.MerchantRevenueCountVO;
import cn.iocoder.yudao.module.api.trade.order.TradeOrderApi;
import cn.iocoder.yudao.module.api.trade.order.dto.TradeOrderItemRespDTO;
import cn.iocoder.yudao.module.api.trade.order.dto.TradeOrderRespDTO;
import cn.iocoder.yudao.module.api.trade.scan.dto.ScanOrderDTO;
import cn.iocoder.yudao.module.shop.revenue.dao.RevenueMapper;
import cn.iocoder.yudao.module.shop.revenue.mq.RevenueProducer;
import cn.iocoder.yudao.module.shop.revenue.pojo.po.ShopRevenue;
import cn.iocoder.yudao.module.shop.revenue.pojo.vo.RevenueVO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * <pre>
 * OOoO0OOoO0OOOooo0oOOOO0OOOOO0oooOO0ooOOO0Ooooo0OOOOo0ooooO0OOooo0Ooooo0OOOOO
 * 服务
 * OOoO0OOoO0OOOooo0oOOOO0OOOOO0oooOO0ooOOO0Ooooo0OOOOo0ooooO0OOooo0Ooooo0OOOOO
 * </pre>
 *
 * @author 山野羡民（1032694760@qq.com）
 * @since 2025/04/30
 */
@Slf4j
@Service
public class CoreRevenueService extends AbstractService<ShopRevenue, RevenueVO> {
    @Resource
    private RevenueMapper revenueMapper;

    @Resource
    private RevenueProducer revenueProducer;

    @Resource
    private ShopInfoApi shopInfoApi;
    @Resource
    private TradeOrderApi tradeOrderApi;

    @Override
    public RevenueMapper getInjectedMapper() {
        return revenueMapper;
    }

    @Transactional(rollbackFor = Exception.class)
    public void createWhenTradeOrderPaid(TradeOrderRespDTO order) {
        Assertions.notNull(order, "交易订单为空");
        List<ShopRevenue> list = getInjectedMapper().selectByShopIdAndTradeNo(order.getShopId(), order.getNo());
        if (CollUtil.isNotEmpty(list)) {
            log.warn("[createWhenScanOrderPaid/TradeOrder][shopId({})][tradeNo({}) 添加营收记录失败：已存在]", order.getShopId(), order.getNo());
            return;
        }
        list = new ArrayList<>();
        double settlementPercent = 100 - shopInfoApi.getServiceFeePercent(order.getShopId());
        List<TradeOrderItemRespDTO> orderItems = tradeOrderApi.getOrderItemsByOrderId(order.getId());
        for (TradeOrderItemRespDTO orderItem : orderItems) {
            ShopRevenue revenue = new ShopRevenue();
            revenue.setShopId(order.getShopId());
            revenue.setTradeNo(order.getNo());
            revenue.setOrderItemId(orderItem.getId());
            revenue.setOrderPrice(orderItem.getPrice());
            revenue.setPayPrice(order.getPayPrice());
            revenue.setOrderSnapshot(JSONUtil.toJsonStr(orderItem));
            int settlementMoney = MoneyUtils.calculateRatePriceFloor(orderItem.getPayPrice(), settlementPercent);
            revenue.setSettlementPercent(settlementPercent);
            revenue.setSettlementMoney(settlementMoney);
            revenue.setSourceUserId(order.getUserId());
            if (settlementMoney == 0) {
                revenue.setStatus(RevenueStatusEnum.CLOSED.getValue());
                revenue.setUnfreezeTime(LocalDateTime.now());
            } else {
                revenue.setStatus(RevenueStatusEnum.FREEZING.getValue());
                revenue.setUnfreezeTime(LocalDateTime.now().plusDays(15));
            }
            revenue.setNote("售卖产品 %s 元，顾客实付 %s 元，收入 %s 元".formatted(MoneyUtils.fenToYuanStr(orderItem.getPrice()), MoneyUtils.fenToYuanStr(orderItem.getPayPrice()), MoneyUtils.fenToYuanStr(settlementMoney)));
            revenue.setCancelTime(null);
            list.add(revenue);
        }
        getInjectedMapper().insertBatch(list);
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateWhenTradeOrderCompleted(TradeOrderRespDTO order) {
        Assertions.notNull(order, "交易订单为空");
        List<ShopRevenue> list = getInjectedMapper().selectByShopIdAndTradeNo(order.getShopId(), order.getNo());
        if (CollUtil.isEmpty(list)) {
            log.warn("[updateWhenTradeOrderCompleted/TradeOrder][shopId({})][tradeNo({}) 更新营收记录失败：不存在]", order.getShopId(), order.getNo());
            return;
        }
        for (ShopRevenue revenue : list) {
            revenue.setStatus(RevenueStatusEnum.UNFREEZE.getValue());
            revenue.setUnfreezeTime(LocalDateTime.now());
        }
        getInjectedMapper().updateById(list);
        int settlementMoney = list.stream().mapToInt(ShopRevenue::getSettlementMoney).sum();
        revenueProducer.sendRevenueUnfreezeMessage(order.getShopId(), order.getNo(), order.getPayPrice(), settlementMoney);
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateWhenTradeAfterSaleCompleted(TradeOrderRespDTO order, TradeOrderItemRespDTO orderItem) {
        Assertions.notNull(order, "交易订单为空");
        ShopRevenue revenue = getInjectedMapper().selectByShopIdAndOrderItemId(order.getShopId(), orderItem.getId());
        if (revenue == null) {
            log.warn("[updateWhenTradeAfterSaleCompleted/TradeOrder][shopId({})][tradeNo({}) orderItemId({}) 更新营收记录失败：不存在]", order.getShopId(), order.getNo(), orderItem.getId());
            return;
        }
        revenue.setStatus(RevenueStatusEnum.CANCEL.getValue());
        revenue.setCancelTime(LocalDateTime.now());
        getInjectedMapper().updateById(revenue);
        revenueProducer.sendRevenueCancelMessage(order.getShopId(), order.getNo(), orderItem.getPayPrice(), revenue.getSettlementMoney());
    }

    @Transactional(rollbackFor = Exception.class)
    public void createWhenScanOrderPaid(ScanOrderDTO order) {
        Assertions.notNull(order, "扫码订单为空");
        List<ShopRevenue> list = getInjectedMapper().selectByShopIdAndTradeNo(order.getShopId(), order.getTradeNo());
        if (CollUtil.isNotEmpty(list)) {
            log.warn("[createWhenScanOrderPaid/ScanOrder][shopId({})][tradeNo({}) 添加营收记录失败：已存在]", order.getShopId(), order.getTradeNo());
            return;
        }
        ShopRevenue revenue = new ShopRevenue();
        revenue.setShopId(order.getShopId());
        revenue.setTradeNo(order.getTradeNo());
        revenue.setOrderItemId(0L);
        revenue.setOrderPrice(order.getOriginPrice());
        revenue.setPayPrice(order.getPrice());
        revenue.setOrderSnapshot(JSONUtil.toJsonStr(order));
        double settlementPercent = 100 - shopInfoApi.getServiceFeePercent(order.getShopId());
        int settlementMoney = MoneyUtils.calculateRatePriceFloor(order.getPrice(), settlementPercent);
        revenue.setSettlementPercent(settlementPercent);
        revenue.setSettlementMoney(settlementMoney);
        revenue.setSourceUserId(order.getUserId());
        if (settlementMoney == 0) {
            revenue.setStatus(RevenueStatusEnum.CLOSED.getValue());
            revenue.setUnfreezeTime(LocalDateTime.now());
        } else {
            revenue.setStatus(RevenueStatusEnum.UNFREEZE.getValue());
            revenue.setUnfreezeTime(LocalDateTime.now());
        }
        revenue.setNote("扫码收款 %s 元，顾客实付 %s 元，收入 %s 元".formatted(MoneyUtils.fenToYuanStr(order.getOriginPrice()), MoneyUtils.fenToYuanStr(order.getPrice()), MoneyUtils.fenToYuanStr(settlementMoney)));
        revenue.setCancelTime(null);
        getInjectedMapper().insert(revenue);
        revenueProducer.sendRevenueUnfreezeMessage(order.getShopId(), order.getTradeNo(), order.getPrice(), settlementMoney);
    }

    @DataPermission(enable = false)
    public MerchantRevenueCountVO getRevenueCount(Long shopId) {
        MerchantRevenueCountVO countVO = new MerchantRevenueCountVO();
        countVO.setFreezingCount(getInjectedMapper().selectFreezingSettlementMoney(shopId));
        countVO.setTodayFreezingCount(getInjectedMapper().selectTodayFreezingSettlementMoney(shopId));
        countVO.setTodayUnfreezeCount(getInjectedMapper().selectTodayUnfreezeSettlementMoney(shopId));
        countVO.setTotalUnfreezeCount(getInjectedMapper().selectTotalUnfreezeSettlementMoney(shopId));
        return countVO;
    }

}
